#ifdef linux
#include<GL/glew.h>
#include<GLFW/glfw3.h>
#else
#include<glew.h>
#include<glfw3.h>
#endif
#include<iostream>
#include<time.h>
#include<math.h>

#include "myBase.h"
#include <stdlib.h>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

class myStateCalls
{
    public:
    static void enableDepth() { glEnable(GL_DEPTH_TEST); }
};
class initState
{
    public:
};
float rotAngleX = 0.0f;
float rotAngleY = 0.0f;

void keyCallback(GLFWwindow *wnd, int key, int scancode, int action, int mods)
{
    switch(key)
    {
        case GLFW_KEY_LEFT:
            rotAngleY += 0.05f;
        break;
        
        case GLFW_KEY_RIGHT:
            rotAngleY -= 0.05f;
        break;
        
        case GLFW_KEY_UP:
            rotAngleX += 0.05f;
        break;
        
        case GLFW_KEY_DOWN:
            rotAngleX -= 0.05f;
        break;
    }    
}

int main()
{
	int errorval = 0;	
	errorval = glfwInit();
    if(!errorval) return 1;
    
    myWindow *window = new myWindow(800,600, "Hello World");    
    
    window->createWindow();
    window->makeCurrent();
    
    glfwSetKeyCallback(window->getWindow(), keyCallback);

    glewExperimental = GL_TRUE;
    glewInit();
	
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    float points[] = { 0.0f, 0.5f, 0.0f,
                       0.5f, -0.5f, 0.0f,
                       -0.5f, -0.5f, 0.0f
                     };

    float times[] = { 
                        sin(time(NULL)) * 0.5f + 0.5f, cos(time(NULL))*0.5f + 0.5f, 0,0,
                        sin(time(NULL)) * 0.5f + 0.5f, cos(time(NULL))*0.5f + 0.5f, 0,0,
                        sin(time(NULL)) * 0.5f + 0.5f, cos(time(NULL))*0.5f + 0.5f, 0,0,

                    };
    glm::mat4 View = glm::mat4(1.0);
    GLint uniformlocation = -1;
    
    GLuint vbo = 0;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), points, GL_STATIC_DRAW);

    GLuint vbo1 = 0;
    glGenBuffers(1, &vbo1);
    glBindBuffer(GL_ARRAY_BUFFER, vbo1);
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), times, GL_DYNAMIC_DRAW);

    GLuint vao = 0;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glVertexAttribPointer(0,3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);


    glBindBuffer(GL_ARRAY_BUFFER, vbo1);
    glVertexAttribPointer(1,4, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(1);


    myShader *vshader = new myShader(myShader::vertexShader, "Vertex Color Pass And Rotate ");
    myShader *pshader = new myShader(myShader::fragmentShader, "Fragment Color Mix");
    myShaderPipe *pipe = new myShaderPipe();

    vshader->createShaderFromFile("glm_vertex.glsl");
    pshader->createShaderFromFile("glm_fragment.glsl");
    vshader->compileShader();
    pshader->compileShader();
    
    pipe->createProgram();
    pipe->attachShader(vshader);
    pipe->attachShader(pshader);
    pipe->linkPipe();

    uniformlocation = glGetUniformLocation(pipe->getHandle(), "rotMatrix");
    if(uniformlocation == -1) {
        std::cout << "\nERROR : Invalid uniform location " ;
        exit(1);
    }
    float sign = 1;
    while(!glfwWindowShouldClose(window->getWindow()))
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glUseProgram(pipe->getHandle());
        glBindVertexArray(vao);
        times[0] = times[4] = times[8] = sin(time(NULL)) * 0.5f + 0.5f;
        times[1] = times[5] = times[9] = cos(time(NULL)) * 0.5f + 0.5f;
        glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), times, GL_DYNAMIC_DRAW);
        glUniformMatrix4fv(uniformlocation, 1, GL_FALSE, glm::value_ptr(View));
        View = glm::rotate(glm::mat4(1.0), rotAngleX, glm::vec3(1,0,0));
        View = glm::rotate(View , rotAngleY, glm::vec3(0,1,0));
   
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glfwPollEvents();
        glfwSwapBuffers(window->getWindow());
    }
    glfwTerminate();
	return 0;
}
